package com.snailhd.common.db;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.*;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import redis.clients.util.Pool;

import java.util.*;

/**
 * @author hd
 * @description
 * @date 2019-08-19 10:37
 */

@Slf4j
public class SimpleRedisClient {

    private Pool<Jedis> jedisPool;

    public SimpleRedisClient(String host,int port,String pwd,int database,int maxIdle,int minIdle,int maxTotal){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        //设置最大闲置个数
        poolConfig.setMaxIdle(maxIdle);
        //设置最小闲置个数：
        poolConfig.setMinIdle(minIdle);
        //设置最大的连接数
        poolConfig.setMaxTotal(maxTotal);
        //创建连接池对象  host:连接redis主机IP ；port:redis的默认端口

        jedisPool = new JedisPool(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, StringUtils.isEmpty(pwd)?null:pwd, database, null);
    }



    protected static final String SET_IF_NOT_EXIST = "NX";

    private static final String SET_WITH_EXPIRE_TIME = "EX";

    private static final String LOCK_SUCCESS = "OK";

    private static final Long RELEASE_SUCCESS = 1L;


    private void close(Jedis jedis){
        if (null != jedis) {
            jedis.close();
        }
    }


    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.get(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }


    public String set(String key, String val) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.set(key,val);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public Set<String> keys(String pattern) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.keys(pattern);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public String setex(String key, int seconds, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.setex(key,seconds,value);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public long expire(String key, int seconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.expire(key,seconds);
        } catch (Exception e) {
            log.error(e.getMessage());
            return 0;
        } finally {
            close(jedis);
        }
    }

    public List<String> mget(String... keys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.mget(keys);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public String hget(String key, String field) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hget(key,field);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public Map<String, String> hgetAll(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hgetAll(key);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public long hset(String key, String field, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hset(key,field,value);
        } catch (Exception e) {
            log.error(e.getMessage());
            return 0;
        } finally {
            close(jedis);
        }
    }

    public String hmset(String key, Map<String, String> map) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hmset(key,map);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public List<String> hmget(String key, String... fields){
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hmget(key,fields);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long del(String... keys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.del(keys);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long hdel(String key, String... fields) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hdel(key,fields);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long lpush(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lpush(key,values);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public List<String> lrange(String key, Long start, Long end) {
        Jedis jedis = null;
        try {
            Long startTemp = start, endTemp = end;
            if (null == startTemp) {
                startTemp = 0L;
            }
            if (null == endTemp) {
                endTemp = -1L;
            }
            jedis = jedisPool.getResource();
            return jedis.lrange(key,startTemp,endTemp);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            close(jedis);
        }
    }

    public List<String> scan(int cursor, String pattern, Integer count) {
        Jedis jedis = null;
        try {
            ScanParams scanParams = new ScanParams();
            int defaultCount = 100;
            boolean queryAll = false;
            if (null != count) {
                defaultCount = count;
            } else {
                queryAll = true;
            }
            scanParams.count(defaultCount);
            scanParams.match(pattern);
            ScanResult<String> result;
            jedis = jedisPool.getResource();
            result = jedis.scan(String.valueOf(cursor), scanParams);
            if (!queryAll) {
                return result.getResult();
            }
            // 模拟查询所有的数据
            List<String> all = new ArrayList<String>();
            String i = result.getStringCursor();
            all.addAll(result.getResult());
            while (!"0".equals(i)) {
                result = jedis.scan(i, scanParams);
                i = result.getStringCursor();
                all.addAll(result.getResult());
            }
            return all;
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public String mset(Map<String, String> map) {
        if (null == map || map.isEmpty()) {
            return null;
        }
        int len = map.size() * 2;
        String[] keysvalues = new String[len];
        List<String> keyvalueList = new ArrayList<String>(len);
        for (Map.Entry<String, String> entry : map.entrySet()) {
            keyvalueList.add(entry.getKey());
            keyvalueList.add(entry.getValue());
        }
        return mset(keyvalueList.toArray(keysvalues));
    }

    public String mset(String... keysvalues) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.mset(keysvalues);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long msetnx(Map<String, String> map) {
        if (null == map || map.isEmpty()) {
            return null;
        }
        int len = map.size() * 2;
        String[] keysvalues = new String[len];
        List<String> keyvalueList = new ArrayList<String>(len);
        for (Map.Entry<String, String> entry : map.entrySet()) {
            keyvalueList.add(entry.getKey());
            keyvalueList.add(entry.getValue());
        }
        return msetnx(keyvalueList.toArray(keysvalues));
    }

    public Long msetnx(String... keysvalues) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.msetnx(keysvalues);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long zrem(String key, String member) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrem(key, member);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long incr(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.incr(key);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long lrem(String key, int count, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lrem(key, count, value);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long hincrBy(String key, String field, Long value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hincrBy(key, field, value);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public Long geoadd(String key, double longitude, double latitude, String member) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geoadd(key, longitude, latitude, member);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            close(jedis);
        }
    }

    public List<GeoRadiusResponse> georadius(String key, double longitude, double latitude, double radius, int num) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            List<GeoRadiusResponse> georadius = jedis.georadius(key, longitude, latitude, radius, GeoUnit.M,
                    GeoRadiusParam.geoRadiusParam().withCoord().withDist().sortAscending().count(num));

            return georadius;
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return null;
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }

    public boolean distributedLock(String lockKey, String requestId, long expireTime) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String ret = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
            return LOCK_SUCCESS.equals(ret);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return false;
        } finally {
            close(jedis);
        }
    }

    public boolean releaseDistributedLock(String lockKey, String requestId) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object obj = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
            return RELEASE_SUCCESS.equals(obj);
        } catch (Exception e) {
            log.error("jedis执行异常......", e);
            return false;
        } finally {
            close(jedis);
        }
    }

    public Integer getConfigStrToInteger(String key, Integer defaultValue) {
        try {
            Integer re = null;
            String value = get(key);
            if(StringUtils.isEmpty(value) ) {
                re = defaultValue;
                if(defaultValue!=null) {
                    set(key,defaultValue+"");
                }
            }else {
                re =  Integer.parseInt(value);
            }
            return re;
        } catch (Exception e) {
            log.error("执行异常",e);
            return defaultValue;
        }
    }


    public Integer hgetConfigStrToInteger(String key, String fields, Integer defaultValue) {
        try {
            Integer re = null;
            String value = hget(key,fields);
            if(StringUtils.isEmpty(value) ) {
                re = defaultValue;
                if(defaultValue!=null) {
                    set(key,defaultValue+"");
                }
            }else {
                re =  Integer.parseInt(value);
            }
            return re;
        } catch (Exception e) {
            log.error("执行异常",e);
            return defaultValue;
        }
    }
}
